'use strict';
import * as sequelize from 'sequelize';
import BaseService from './base';
import { IAricleAttr, IArticleInst } from '../model/article';
import { createRule, updateRule } from '../rules/article';
const { Op } = sequelize;

// const errors = this.app.validator.validate({ id: 'id' }, this.request.body);
// include: [[Sequelize.fn('SUM', Sequelize.col('pvCount')), 'pv']],
interface IArticleQueryParams {
  page?: number;
  limit?: number;
  author?: string;
  title?: string;
  type?: string;
  startTime?: string;
  endTime?: string;
}

export default class extends BaseService {
  async findByPk(id: number) {
    const { ctx } = this;
    return await ctx.model.Article.findByPk(id);
  }
  async getInfo(id: number): Promise<IArticleInst> {
    const { ctx } = this;
    return this.ctx.model.Article.findByPk(id, {
      include: [{
        model: ctx.model.User,
        as: 'author',
        attributes: { exclude: ['password'] },
      }],
    });
  }
  async list({ author, title, startTime, endTime, type }: IArticleQueryParams) {
    const { ctx, service, app } = this;
    const CATEGORIES = app.config.categories;
    const queryParams: any = {};
    if (author) {
      const user = await service.user.getByName(author);
      if (user) {
        queryParams.authorId = user.id;
      } else {
        queryParams.authorId = null;
      }
    }
    if (title) {
      queryParams.title = { [Op.like]: `%${title}%` };
    }
    if (type) {
      if (type === 'good') {
        queryParams.good = true;
      } else {
        const category = CATEGORIES[type];
        queryParams.category = category ? category : type;
      }
    }
    if (startTime && !endTime) {
      queryParams.createdAt = { [Op.gte]: new Date(startTime) };
    } else if (!startTime && endTime) {
      queryParams.createdAt = { [Op.lte]: new Date(endTime) };
    } else if (startTime && endTime) {
      queryParams.createdAt = { [Op.gte]: new Date(startTime), [Op.lte]: new Date(endTime) };
    }

    const defaultSort: string[][] = [
      ['top', 'DESC'],
      ['lastCommentTime', 'DESC'],
      ['updatedAt', 'DESC'],
    ];

    const { list, pagination } = await this.pagination(ctx.model.Article, {
      where: queryParams,
      attributes: {
        exclude: ['deletedAt'],
      },
      include: [{
        model: ctx.model.User,
        as: 'author',
        attributes: { exclude: ['password'] },
      }],
      order: defaultSort,
    });

    return {
      list,
      pagination,
    };
  }
  /**
   * @description: 获取用户文章
   * @param {type}
   * @return:
   */
  async getUserLikeArticles(userId: number) {
    const { ctx } = this;
    return await ctx.model.ArticleLike.findAll({
      where: {
        userId,
      },
    });
  }

  /**
   * @description: 保存
   * @param {type}
   * @return:
   */
  async doSave(payload: IAricleAttr): Promise<IArticleInst> {
    const { ctx } = this;
    ctx.validate(createRule, payload);
    return await ctx.model.Article.create(payload);
  }

  /**
   * @description: 编辑
   * @param {number} id 文章ID
   * @param {object} payload 更新values
   * @return:
   */
  async doUpdate(id: number, payload: IAricleAttr) {
    const { ctx } = this;
    ctx.validate(updateRule, payload);
    payload.status = 2;
    delete payload.authorId;
    return await ctx.model.Article.update(payload, {
      where: {
        id,
      },
    });
  }

  /**
   * @description: 点赞
   * @param {number} commentId 评论ID
   * @param {number} userId 用户ID
   * @return:
  */
  async toggleLike(articleId: number, userId: number) {
    const { ctx } = this;
    const article = await ctx.model.Article.findByPk(articleId);
    if (!article) {
      ctx.fail('文章不存在', 404001)
      return;
    }
    let isLike: boolean;
    let condition: object;
    const query = {
      articleId,
      userId,
    };
    const articleLike = await ctx.model.ArticleLike.scope('all').findOne({
      where: query,
    });
    if (articleLike) {
      if (articleLike.status === 1) {
        condition = { status: 0 };
        isLike = false;
      } else {
        condition = { status: 1 };
        isLike = true;
      }
      await ctx.model.ArticleLike.scope('all').update(condition, {
        where: query,
      });
    } else {
      await ctx.model.ArticleLike.create({
        status: 1,
        userId,
        articleId,
      });
      isLike = true;
    }
    await this.updateCount(articleId, 'likeCount', isLike);
    const count = await ctx.model.ArticleLike.count({
      where: {
        articleId,
      },
    });
    return {
      userId,
      isLike,
      count,
    };
  }

  /**
   * @description: 获取文章点赞用户
   * @param {number} id 文章ID
   * @return:
  */
  async getLikeUsersByArticleId(id: number) {
    const { ctx } = this;
    const result = await ctx.model.Article.findByPk(id, {
      include: [
        {
          model: ctx.model.User,
          as: 'likeUsers',
          attributes: ['id', 'username', 'email', 'avatar', 'gender'],
          through: {
            attributes: [],
            where: {
              status: 1,
            },
          },
        },
      ],
    });
    if (result) {
      return result.likeUsers;
    } else {
      return [];
    }
  }

  /**
   * @description: 文章收藏
   * @param {number} articleId 文章ID
   * @param {number} userId 用户ID
   * @return:
  */
  async toggleCollect(articleId: number, userId: number) {
    const { ctx } = this;
    const article = await ctx.model.Article.findByPk(articleId);
    if (!article) {
      ctx.fail('文章不存在', 404001)
      // ctx.throwBizError({ message: '文章不存在', log: false });
      return;
    }
    let isCollect: boolean;
    let condition: object;
    const query = {
      articleId,
      userId,
    };
    const articleCollection = await ctx.model.ArticleCollection.scope('all').findOne({
      where: query,
    });
    if (articleCollection) {
      if (articleCollection.status === 1) {
        condition = { status: 0 };
        isCollect = false;
      } else {
        condition = { status: 1 };
        isCollect = true;
      }
      await ctx.model.ArticleCollection.scope('all').update(condition, {
        where: query,
      });
    } else {
      await ctx.model.ArticleCollection.create({
        status: 1,
        userId,
        articleId,
      });
      isCollect = true;
    }
    await this.updateCount(articleId, 'collectionCount', isCollect);
    const count = await ctx.model.ArticleCollection.count({
      where: {
        articleId,
      },
    });
    return {
      userId,
      isCollect,
      count,
    };
  }

  /**
   * @description: 批量删除
   * @param {number} id 文章ID
   * @param {object} payload 更新values
   * @return:
   */
  // 删除
  batchRemove(articleIds: number[], userId: number) {
    const { ctx } = this;
    return ctx.model.Article.update({
      status: 0,
    }, { where: { id: { [Op.in]: articleIds }, authorId: userId } });
  }
  
  /**
   * @description: 更新数量
   * @param {number} id 文章ID
   * @param {object} payload 更新values
   * @return:
   */
  async updateCount(articleId: number, field: string, inc?: boolean) {
    const { ctx } = this;
    const article = await ctx.model.Article.findByPk(articleId);
    const attr: any = field;
    if (article) {
      if (inc) {
        return await article.increment(attr);
      } else {
        return await article.decrement(attr);
      }
    }
    return;
  }
}
